用 React Router 或 Vue Router 的時候,路由是一份要自己維護的清單:在某個檔案裡把網址和元件一條條註冊起來。換到 Astro,官方說「不需要路由設定」,檔案和網址的對應改由 src/pages/ 的位置決定。
檔案的位置,就是網址。src/pages/ 底下的檔案樹,會直接變成你網站的網址樹,中間沒有另一份對照表。
寫過 Nuxt 的話,這套機制其實不陌生:Nuxt 的 pages/ 也是這樣。差別在於,這裡不用像 Vue Router(SPA)那樣手寫 routes:[]。先看「檔案怎麼變網址」;少了那張總表,大專案可以改用工具總覽所有路由。
把檔案放進 src/pages/,Astro 就會按照檔案路徑產生網址。
官方文件的靜態路由對照:
src/pages/index.astro -> /
src/pages/about.astro -> /about
src/pages/about/index.astro -> /about
src/pages/about/me.astro -> /about/me
src/pages/posts/1.md -> /posts/1
這裡有兩個容易混淆的地方。index.astro 對應的是「那層資料夾的根」,所以 about/index.astro 和 about.astro 都是 /about;.md 檔也能直接當一個頁面。
下面列出這個實作專案的 src/pages,右側是每個檔案對應的網址:
src/pages/index.astro -> /
src/pages/blog/[...slug].astro -> /blog/(文章路徑)
src/pages/demos/feedback-action.astro -> /demos/feedback-action
src/pages/bench/index.astro -> /bench
src/pages/bench/vue-directives.astro -> /bench/vue-directives
src/pages/api/feedback.json.ts -> /api/feedback.json
最後一個 .ts 是回傳 JSON 的 endpoint;它雖然不算頁面,仍和一般頁面放在同一個 pages 樹裡。Day 20 再細講。
[ ],就是動態路由文章有幾百篇時,不必建幾百個 .astro。把參數用中括號包進檔名,就能建立動態路由:
src/pages/blog/[slug].astro:[slug] 是一段會變動的參數,/blog/hello、/blog/world 都會由這個檔案處理。src/pages/blog/[...slug].astro:多了 ...,叫 catch-all(rest 參數),可以匹配含有 / 的多段路徑,像 /blog/2026/hello。[id] 這種寫法是單段動態路由,[...] 則是能匹配多段的版本。差別在能不能匹配斜線:單層 [slug] 只匹配一段,一旦 slug 裡有 / 就無法匹配,[...slug] 才行。
這個專案的 blog 因此採用 [...slug].astro。目前 4 篇文章都是平的(day-01-why-astro 這種單層 slug),用 [slug] 就夠。採用 catch-all 是為了保留多層文章路徑:blog 的內容 loader 會遞迴掃描資料夾(glob pattern 用 **/)。如果之後把文章放進子資料夾,slug 就可能帶 /;這時 [slug] 會無法匹配,[...slug] 才能處理。官方文件也明確寫道:slug 含 /、要產出多段 URL 的頁面時,必須用 rest 參數。Astro 官方 blog 範本預設採用 catch-all,理由相同。
動態網址要在 build 時先產好,還是收到請求才產生,會牽涉 getStaticPaths 和 SSG/SSR,Day 15 再談。這裡先釐清檔名如何決定路由。
Astro 文件沒有專門解釋「為什麼用 file-based routing」,只交代它的機制:不需要設定檔,把檔案加進 src/pages/ 就會自動產生路由。整體設計原則中,有兩條和這項機制相符:content-driven(為呈現內容而設計)與易用(讓沒有專家知識的人也能建站)。使用者不必先學一套路由設定,加個檔案就有頁面,符合「易用」原則。(來源:Astro 官方 concepts/why-astro,查證日 2026-07-19;這是把整體原則對應到 routing,官方沒有 routing 專屬的理由說明。)
file-based routing 減少了幾種容易出錯的情況:
routes:[] 和元件分開維護;改了元件卻忘了改路由表,或反過來,兩邊就會對不上。file-based routing 直接用檔案表示路由,不會再有第二份清單需要同步。/blog/x 出問題,可以直接去 src/pages/blog/ 找檔案,中間不隔一層對照表。人比較容易找,AI 工具也比較容易沿著檔案結構定位。大專案仍有總覽所有路由的需求。在 file-based routing 裡,工具可以根據檔案自動產生這張表,並隨檔案更新:
find src/pages(或編輯器的檔案樹)就是一份會隨檔案同步更新的路由清單。
file-based routing 的路由總表不用手動維護;直接看檔案樹或 build 產出即可。
src/pages 裡的檔案才是路由。 src/components、src/layouts 裡的 .astro 只會被其他頁面 import,不會自己變成網址。想「新增一頁」卻沒反應,先確認檔案是否放對資料夾。about/index.astro 和 about.astro 都是 /about。 兩種都可以,別兩個同時放,造成同一個網址兩個來源。/,就不要用單層 [slug]。 [slug] 無法匹配 /blog/2026/hello,要改用 [...slug]。src/pages 裡的每個檔案都是路由,包括你以為已經停用的檔案。 想停用一頁,要把檔案移出 src/pages;只改檔名不算。這一點在真實專案裡很容易讓人找錯方向。我複製了一個上線中的多語系品牌官網來跑 build,astro build 直接失敗。原因是 src/pages/ 裡留著一個舊版首頁,檔名加上 -bak 當作「已停用」。但它仍是一條路由,所以照樣進入建置;它 import 的舊元件又 import 另一個元件,最後連到一個已不存在的 export。錯誤訊息只指出第三層檔案,與 -bak 頁隔了兩層,很容易從錯的地方開始查。把 -bak 檔移出 src/pages 後,build 就通過了。
檔名加 -bak 當停用,在其他資料夾沒有問題;放進 src/pages,卻會多出一條沒人維護的路由。舊版若要保留,交給版本控制,或搬到 src/pages 外面。
打開任何一個 Astro 專案的 src/pages,先不查文件,逐一說出每個檔案對應的網址;再看檔名有沒有 [ ] 和 ...,判斷它是固定頁、單段動態路由,還是能匹配多段的 catch-all。
檔案變成網址後,接著要處理每一頁都會用到的 header、footer 和共用外框。Day 4 會用 layout 和 slot 把共用外框抽出來,讓這些 .astro 頁不必各自重寫。
本日程式碼:step-03|只看這天的改動:step-02...step-03